/*
 * @Author: WHAlex
 * @Date: 2025-01-20 09:29:43
 *
 * Copyright (c) 2025 by atguigu, All Rights Reserved.
 */
#include "App_WS.h"

esp_websocket_client_handle_t sound_client;
esp_websocket_client_handle_t video_client;

static const char *TAG = "websocket";

// 定义两个标志位表示哪一个关闭按钮被点击
static uint8_t is_sending = 0;
static uint8_t is_receing = 0;

static uint8_t is_del_video_task = 0;

// 声明环形缓冲区
static RingbufHandle_t ringBuf;

// 声明任务句柄
static TaskHandle_t mic_ringbuf_task_handler;
static TaskHandle_t ringbuf_ws_task_handler;
static TaskHandle_t app_ws_video_task_handler;

// 定义删除任务的标志位
volatile uint8_t delTasks = 0;

/**
 * @description: 从Mic读取数据存入环形缓冲区任务
 * @param {void *} args
 * @return {*}
 */
void app_mic_ringbuf_task(void *args)
{
    MY_LOGE("开启从Mic读取数据存入环形缓冲区任务...");
    uint8_t data[1024 - 8] = {0};
    while (1)
    {
        /**
         * 读取Mic数据
         * 采样率:16K表示每秒采样16K次
         * 位深:16  表示每次采样为2个字节
         * 1s采集  32K个字节
         * 10ms    320个字节的数据
         */
        Inf_ES8311_ReadData(data, sizeof(data));

        // 存入环形缓冲区
        xRingbufferSend(ringBuf, data, sizeof(data), portMAX_DELAY);

        // 删除任务
        if (delTasks)
        {
            MY_LOGE("删除Mic -> RingBuffer任务...");
            delTasks--;
            vTaskDelete(NULL);
        }

        vTaskDelay(10);
    }
}

/**
 * @description: 从环形缓冲区读取数据并通用WS客户端发送到服务器任务
 * @param {void *} args
 * @return {*}
 */
void app_ringbuf_ws_task(void *args)
{
    MY_LOGE("开启从缓冲区到服务器任务...");
    size_t len = 0;
    while (1)
    {
        // 从缓冲区读取数据
        char *data = xRingbufferReceive(ringBuf, &len, 2000);

        // 将读取到的数据发送至服务器
        if (len > 0)
        {
            App_WS_Send_bin(sound_client, data, len);

            // 归还空间
            vRingbufferReturnItem(ringBuf, data);
        }

        // 删除任务
        if (delTasks)
        {
            MY_LOGE("删除 RingBuffer -> WS 任务...");
            delTasks--;
            vTaskDelete(NULL);
        }

        vTaskDelay(10);
    }
}

/**
 * @description: 获取图片发送到服务器任务
 * @param {void*} args
 * @return {*}
 */
void App_WS_Video_Task(void *args)
{
    uint8_t *data;
    size_t len = 0;
    while (1)
    {
        // 获取摄像头图片
        Inf_OV2640_TakePic(&data, &len);

        // 发送至服务器
        if (len > 0)
        {
            App_WS_Send_bin(video_client, (char *)data, len);
            // 释放资源
            Inf_OV2640_ReturnPic();
        }

        if (is_del_video_task)
        {
            is_del_video_task = 0;
            vTaskDelete(NULL);
        }

        vTaskDelay(10);
    }
}

/**
 * @description: WebSocket回调函数
 * @param {void} *handler_args
 * @param {esp_event_base_t} base
 * @param {int32_t} event_id
 * @param {void} *event_data
 * @return {*}
 */
static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
    switch (event_id)
    {
    case WEBSOCKET_EVENT_BEGIN:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_BEGIN");
        break;
    case WEBSOCKET_EVENT_CONNECTED:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED");
        break;
    case WEBSOCKET_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED");
        break;
    case WEBSOCKET_EVENT_DATA:
        if (data->op_code == 0x2)
        {
            // MY_LOGE("收到数据...");
            Inf_ES8311_WriteData(data->data_ptr, data->data_len);
        }
        break;
    case WEBSOCKET_EVENT_ERROR:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR");
        break;
    case WEBSOCKET_EVENT_FINISH:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_FINISH");
        break;
    }
}

/**
 * @description: 初始化客户端
 * @return {*}
 */
void App_WS_Init(void)
{
    // ESP中WS客户端的配置信息
    esp_websocket_client_config_t websocket_cfg = {
        .uri = "ws://192.168.2.6:8000/ws/from_esp",
    };

    // 初始化音频客户端
    sound_client = esp_websocket_client_init(&websocket_cfg);

    // 注册回调函数
    esp_websocket_register_events(sound_client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)sound_client);

    // 创建环形缓冲区
    if (ringBuf == NULL)
    {
        ringBuf = xRingbufferCreate(16 * 1024, RINGBUF_TYPE_NOSPLIT);
    }

    // 给定视频客户端的连接地址
    websocket_cfg.uri = "ws://192.168.2.6:8000/ws/image";
    video_client = esp_websocket_client_init(&websocket_cfg);
}

/**
 * @description: 启动音频客户端
 * @return {*}
 */
void App_WS_Start_Sound_Client(uint8_t dir)
{
    // 客户端已经初始化并且未连接
    if (sound_client != NULL && !esp_websocket_client_is_connected(sound_client))
    {
        MY_LOGE("开启音频客户端...");
        esp_websocket_client_start(sound_client);
    }

    if (dir == DIR_ESP2CLIENT)
    {
        is_sending = 1;

        delTasks = 0;

        // 开启两个任务
        // 任务一:从Mic读取数据将其写入缓冲区
        if (mic_ringbuf_task_handler == NULL)
        {
            xTaskCreate(app_mic_ringbuf_task,
                        "app_mic_ringbuf_task",
                        4096,
                        NULL,
                        5,
                        &mic_ringbuf_task_handler);
        }

        // 任务二:从缓冲区读取数据,通过WS客户端发送到服务器
        if (ringbuf_ws_task_handler == NULL)
        {
            xTaskCreate(app_ringbuf_ws_task,
                        "app_ringbuf_ws_task",
                        4096,
                        NULL,
                        5,
                        &ringbuf_ws_task_handler);
        }
    }
    else if (dir == DIR_CLIENT2ESP)
    {
        is_receing = 1;
    }
}

/**
 * @description: 关闭音频客户端
 * @return {*}
 */
void App_WS_Stop_Sound_Client(uint8_t dir)
{
    if (dir == DIR_ESP2CLIENT)
    {
        is_sending = 0;

        // 修改删除任务标志位,2个任务待删除
        delTasks = 2;

        // 删除两个任务
        if (mic_ringbuf_task_handler != NULL)
        {
            // vTaskDelete(mic_ringbuf_task_handler);
            mic_ringbuf_task_handler = NULL;
        }

        if (ringbuf_ws_task_handler != NULL)
        {
            MY_LOGE("RingBuffer任务 -> WS任务...");
            // vTaskDelete(ringbuf_ws_task_handler);
            ringbuf_ws_task_handler = NULL;
        }
    }
    else if (dir == DIR_CLIENT2ESP)
    {
        is_receing = 0;
    }

    if (is_sending == 0 && is_receing == 0)
    {
        // 关闭客户端,客户端已经初始化并且是已连接状态
        if (sound_client != NULL && esp_websocket_client_is_connected(sound_client))
        {
            MY_LOGE("关闭客户端...");
            esp_websocket_client_stop(sound_client);
        }
    }
}
/**
 * @description: 启动视频客户端
 * @return {*}
 */
void App_WS_Start_Video_Client(void)
{
    // 视频客户端已经初始化并且未连接
    if (video_client != NULL && !esp_websocket_client_is_connected(video_client))
    {
        MY_LOGE("启动视频客户端...");
        esp_websocket_client_start(video_client);

        // 创建任务用于读取摄像头图片并通过WS客户端发送到服务器
        if (app_ws_video_task_handler == NULL)
        {
            xTaskCreate(App_WS_Video_Task,
                        "App_WS_Video_Task",
                        8192,
                        NULL,
                        24,
                        &app_ws_video_task_handler);
        }
    }
}

/**
 * @description: 关闭视频客户端
 * @return {*}
 */
void App_WS_Stop_Video_Client(void)
{
    // 视频客户端已经初始化并且已连接
    if (video_client != NULL && esp_websocket_client_is_connected(video_client))
    {
        MY_LOGE("关闭视频客户端...");
        esp_websocket_client_stop(video_client);

        if (app_ws_video_task_handler != NULL)
        {
            is_del_video_task = 1;
            app_ws_video_task_handler = NULL;
        }
    }
}

/**
 * @description: 通过WS客户端发送二进制数据
 * @param {esp_websocket_client_handle_t} client  客户端
 * @param {uint8_t} data                          要发送的数据
 * @param {size_t} len                            数据长度
 * @return {*}
 */
void App_WS_Send_bin(esp_websocket_client_handle_t client, char *data, size_t len)
{
    if (client != NULL && esp_websocket_client_is_connected(client) && data != NULL && len > 0)
    {
        esp_websocket_client_send_bin(client, data, len, portMAX_DELAY);
    }
}